#include "dma.h"

uint32 count_init[16];         //用来保存16个通道的初始化计数值
#define COUNTSADDR   0x4004000C  //(&counttempaddr)
#define COUNTDADDR   0x4004000C  //(&counttempaddr)

typedef enum DMA_PORTx2BUFF_cfg
{
    DMA_rising          = 0x01u,            //上升沿触发
    DMA_falling         = 0x02u,            //下降沿触发
    DMA_either          = 0x03u,            //跳变沿触发

    //用最高两位标志上拉和下拉
    DMA_rising_down     = 0x81u,            //上升沿触发，源地址IO端口内部下拉
    DMA_falling_down    = 0x82u,            //下降沿触发，源地址IO端口内部下拉
    DMA_either_down     = 0x83u,            //跳变沿触发，源地址IO端口内部下拉

    DMA_rising_up       = 0xc1u,            //上升沿触发，源地址IO端口内部上拉
    DMA_falling_up      = 0xc2u,            //下降沿触发，源地址IO端口内部上拉
    DMA_either_up       = 0xc3u,            //跳变沿触发，源地址IO端口内部上拉

    //用位6来标志，传输结束后,目的地址保持不变，不恢复成原来地址
    DMA_rising_keepon          = 0x21u,     //上升沿触发                      ，目的地址保持不变
    DMA_falling_keepon         = 0x22u,     //下降沿触发                      ，目的地址保持不变
    DMA_either_keepon          = 0x23u,     //跳变沿触发                      ，目的地址保持不变

    DMA_rising_down_keepon     = 0xA1u,     //上升沿触发，源地址IO端口内部下拉，目的地址保持不变
    DMA_falling_down_keepon    = 0xA2u,     //下降沿触发，源地址IO端口内部下拉，目的地址保持不变
    DMA_either_down_keepon     = 0xA3u,     //跳变沿触发，源地址IO端口内部下拉，目的地址保持不变

    DMA_rising_up_keepon       = 0xF1u,     //上升沿触发，源地址IO端口内部上拉，目的地址保持不变
    DMA_falling_up_keepon      = 0xF2u,     //下降沿触发，源地址IO端口内部上拉，目的地址保持不变
    DMA_either_up_keepon       = 0xF3u,     //跳变沿触发，源地址IO端口内部上拉，目的地址保持不变

} DMA_PORTx2BUFF_cfg, DMA_Count_cfg;
/*************************************************************************
*
*  函数名称：DMA_count_Init
*  功能说明：DMA累加计数初始化
*  参数说明：DMA_CHn              通道号（DMA_CH0 ~ DMA_CH15）
*            PTxn                 触发端口
*            count                累加计数中断值
*            DMA_Count_cfg        DMA传输配置
*  函数返回：无
*  修改时间：2012-1-20
*  备    注：
*************************************************************************/
void DMA_Count_Init(DMA_CHn CHn, PTX_n ptxn, uint32 count, uint32 cfg)
{
    uint8 byten = DMA_BYTE1;
    uint8 BYTEs = (byten == DMA_BYTE1 ? 1 : (byten == DMA_BYTE2 ? 2 : (byten == DMA_BYTE4 ? 4 : 16 ) ) ); //计算传输字节数
    if(count > 0x7FFF )count = 0x7FFF;
    count_init[CHn] = count;

    /* 开启时钟 */
    SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;                        //打开DMA模块时钟
    SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;                     //打开DMA多路复用器时钟

    /* 配置 DMA 通道 的 传输控制块 TCD ( Transfer Control Descriptor ) */
//		DMA0->TCD[CHn].SADDR = 0;
    DMA0->TCD[CHn].SADDR =    (uint32)COUNTSADDR;                    // 设置  源地址
//		DMA0->TCD[CHn].DADDR = 0;    
    DMA0->TCD[CHn].DADDR =    (uint32)COUNTDADDR;                    // 设置目的地址
    DMA0->TCD[CHn].SOFF = 0;                                
//    DMA0->TCD[CHn].SOFF = 0x00u;                            // 设置源地址偏移 = 0x0, 即不变
		DMA0->TCD[CHn].DOFF = 0;                                  // 每次传输后，目的地址不变
	
//		DMA0->TCD[CHn].ATTR = 0;
    DMA0->TCD[CHn].ATTR  =    (0
                         | DMA_ATTR_SMOD(0x0)                // 源地址模数禁止  Source address modulo feature is disabled
                         | DMA_ATTR_SSIZE(byten)             // 源数据位宽 ：DMA_BYTEn  。    SSIZE = 0 -> 8-bit ，SSIZE = 1 -> 16-bit ，SSIZE = 2 -> 32-bit ，SSIZE = 4 -> 16-byte
                         | DMA_ATTR_DMOD(0x0)                // 目标地址模数禁止
                         | DMA_ATTR_DSIZE(byten)             // 目标数据位宽 ：DMA_BYTEn  。  设置参考  SSIZE
                        );

    DMA0->TCD[CHn].CITER_ELINKNO  = DMA_CITER_ELINKNO_CITER(count); //当前主循环次数
    DMA0->TCD[CHn].BITER_ELINKNO  = DMA_BITER_ELINKYES_BITER(count);//起始主循环次数

    DMA0->CR &= ~DMA_CR_EMLM_MASK;                            // CR[EMLM] = 0

    DMA0->TCD[CHn].NBYTES_MLNO =   DMA_NBYTES_MLNO_NBYTES(BYTEs); // 通道每次传输字节数，这里设置为BYTEs个字节。注：值为0表示传输4GB */

    /* 配置 DMA 传输结束后的操作 */
    DMA0->TCD[CHn].SLAST      =   -count;                              //调整  源地址的附加值,主循环结束后恢复  源地址
    DMA0->TCD[CHn].DLAST_SGA  =   0;                                  //调整目的地址的附加值,主循环结束后恢复目的地址或者保持地址
//    DMA0->TCD[CHn].CSR = 0;		
    DMA0->TCD[CHn].CSR        =   (0
                             | DMA_CSR_DREQ_MASK            //主循环结束后停止硬件请求
                             | DMA_CSR_INTMAJOR_MASK        //主循环结束后产生中断
                            );

    /* 配置 DMA 触发源 */  //可能要修改  有些不同
    DMAMUX0->CHCFG[CHn] = (0
            | DMAMUX_CHCFG_ENBL_MASK                        /* Enable routing of DMA request */
            | DMAMUX_CHCFG_SOURCE((ptxn >> 5) + DMA_PORTA) /* 通道触发传输源:     */
                                             );

    SIM->SCGC5 |= (SIM_SCGC5_PORTA_MASK << (ptxn>>5));                                                               //开启PORTx端口
		
		//移植龙邱库，移植时可能出现问题的主要是这里，配引脚功能，其他地方只是改改寄存器名称
		gpio_init((PTX_n )ptxn, GPI, 0);
		port_init((PTX_n )ptxn , DMA_FALLING |ALT1 | PULLUP );		//初始化 DMA 管脚，DMA_EITHER跳变沿触发中断，复用功能为GPIO并设置为输入，上拉电阻
		
    /* 开启中断 */
    DMA_EN(CHn);                                    //使能通道CHn 硬件请求
    DMA_IRQ_EN(CHn);                                //允许DMA通道传输
}

/**************************************************************************                             野火嵌入式开发工作室
*
*  函数名称：DMA_count_get
*  功能说明：返回累加计数值
*  参数说明：DMA_CHn              通道号（DMA_CH0 ~ DMA_CH15）
*  函数返回：累加计数值
*  修改时间：2012-3-320
*  备    注：
*************************************************************************/
uint32 DMA_Count_Get(DMA_CHn CHn)
{
	uint32 temp =  count_init[CHn] - ((DMA0)->TCD[CHn].CITER_ELINKNO)  ;
	return temp;
}

void DMA_Count_Reset(DMA_CHn CHn)
{
  ((DMA0)->TCD[CHn].CITER_ELINKNO) = count_init[CHn] ;
}


//void DMA_CH4_Handler(void)
//{
//    DMA_IRQ_CLEAN(DMA_CH4);                                 //清除通道传输中断标志位    (这样才能再次进入中断)
//    DMA_DIS(DMA_CH4);                                       //采集完H个数据后进入这个DMA中断，停止DMA传输。行中断中打开DMA传输
//    /********************/
//    //串口调试用到
//   // if(V_Cnt >= 319)
//   // {
//    //  V_Cnt = 0;
//     // Is_SendPhoto = 1;
//  //  }
//      
//    /*******************/
//}


